package org.zoomdev.zoom.dao.ddl.utils;


import org.zoomdev.zoom.dao.ddl.*;
import org.zoomdev.zoom.dao.meta.ColumnMeta;
import org.zoomdev.zoom.dao.meta.IndexMeta;
import org.zoomdev.zoom.dao.meta.TableMeta;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public final class DDLClassParser {

    public static TableMeta parse(Class<?> clazz) {
        if (!clazz.isAnnotationPresent(_DDL_Table.class)) {
            return null;
        }

        TableMeta tableMeta = new TableMeta();

        // 1. 解析表级注解
        parseTableAnnotation(clazz, tableMeta);

        // 2. 解析字段
        List<ColumnMeta> columns = new ArrayList<>();
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(_DDL_Column.class)) {
                ColumnMeta columnMeta = parseField(field);
                columns.add(columnMeta);
            }
        }
        tableMeta.setColumns(columns.toArray(new ColumnMeta[0]));

        // 3. 解析主键、唯一约束和索引
        List<String> primaryKeys = new ArrayList<>();
        List<IndexMeta> indexes = new ArrayList<>();

        parsePrimaryKeys(clazz, primaryKeys);
        parseUniques(clazz, indexes);
        parseIndexes(clazz, indexes);

        tableMeta.setPrimaryKeys(primaryKeys.toArray(new String[0]));
        tableMeta.setIndexes(indexes.toArray(new IndexMeta[0]));

        return tableMeta;
    }

    private static void parseTableAnnotation(Class<?> clazz, TableMeta tableMeta) {
        _DDL_Table tableAnno = clazz.getAnnotation(_DDL_Table.class);
        if (tableAnno != null) {
            tableMeta.setName(tableAnno.name());
            tableMeta.setComment(tableAnno.comment());
            tableMeta.setEngine(tableAnno.engine());
        }
    }

    private static ColumnMeta parseField(Field field) {
        ColumnMeta columnMeta = new ColumnMeta();
        _DDL_Column columnAnno = field.getAnnotation(_DDL_Column.class);

        columnMeta.setName(columnAnno.name());
        columnMeta.setComment(columnAnno.comment());
        columnMeta.setType(columnAnno.type());
        if (columnAnno.type().hasLength()) {
            columnMeta.setSize(columnAnno.size());
        } else if (columnAnno.type().hasScale()) {
            columnMeta.setSize(columnAnno.size());
            columnMeta.setScale(columnAnno.scale());
        }

        columnMeta.setNotNull(columnAnno.notNull());
        columnMeta.setAutoIncrement(columnAnno.autoIncrement());

        // 处理默认值
        if (!columnAnno.defaultValue().isEmpty()) {
            columnMeta.setDefaultValue(columnAnno.defaultValue());
        }

        if (columnAnno.values().length > 0) {
            columnMeta.setValues(columnAnno.values());
        }

        return columnMeta;
    }

    private static void parsePrimaryKeys(Class<?> clazz, List<String> primaryKeys) {
        // 处理单字段主键
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(_DDL_Primary.class)) {
                primaryKeys.add(field.getAnnotation(_DDL_Column.class).name());
            }
        }

        // 处理复合主键
        if (clazz.isAnnotationPresent(_DDL_CompoundPrimary.class)) {
            _DDL_CompoundPrimary primaryAnno = clazz.getAnnotation(_DDL_CompoundPrimary.class);
            Collections.addAll(primaryKeys, primaryAnno.columns());
        }
    }

    private static void parseUniques(Class<?> clazz, List<IndexMeta> indexes) {
        // 单字段唯一约束
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(_DDL_Unique.class)) {
                String columnName = field.getAnnotation(_DDL_Column.class).name();
                String name = field.getAnnotation(_DDL_Unique.class).name();

                if (name.isEmpty()) {
                    name = "uk_" + columnName;
                }

                IndexMeta index = new IndexMeta();
                index.setName(name);
                index.setUnique(true);
                index.setColumns(new String[]{columnName});
                indexes.add(index);
            }
        }

        // 多字段唯一约束
        if (clazz.isAnnotationPresent(_DDL_CompoundUnique.class)) {
            _DDL_CompoundUnique uniqueAnno = clazz.getAnnotation(_DDL_CompoundUnique.class);
            addUniqueIndex(uniqueAnno, indexes);
        }

        // 多字段唯一约束组
        if (clazz.isAnnotationPresent(_DDL_CompoundUniqueGroup.class)) {
            _DDL_CompoundUniqueGroup groupAnno = clazz.getAnnotation(_DDL_CompoundUniqueGroup.class);
            for (_DDL_CompoundUnique uniqueAnno : groupAnno.value()) {
                addUniqueIndex(uniqueAnno, indexes);
            }
        }
    }

    private static void parseIndexes(Class<?> clazz, List<IndexMeta> indexes) {
        // 单字段索引
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(_DDL_Index.class)) {
                String columnName = field.getAnnotation(_DDL_Column.class).name();
                String name = field.getAnnotation(_DDL_Index.class).name();

                if (name.isEmpty()) {
                    name = "idx_" + columnName;
                }

                IndexMeta index = new IndexMeta();
                index.setName(name);
                index.setUnique(false);
                index.setColumns(new String[]{columnName});
                indexes.add(index);
            }
        }

        // 多字段索引
        if (clazz.isAnnotationPresent(_DDL_CompoundIndex.class)) {
            _DDL_CompoundIndex indexAnno = clazz.getAnnotation(_DDL_CompoundIndex.class);
            addRegularIndex(indexAnno, indexes);
        }

        // 多字段索引组
        if (clazz.isAnnotationPresent(_DDL_CompoundIndexGroup.class)) {
            _DDL_CompoundIndexGroup groupAnno = clazz.getAnnotation(_DDL_CompoundIndexGroup.class);
            for (_DDL_CompoundIndex indexAnno : groupAnno.value()) {
                addRegularIndex(indexAnno, indexes);
            }
        }
    }

    private static void addUniqueIndex(_DDL_CompoundUnique uniqueAnno, List<IndexMeta> indexes) {
        IndexMeta index = new IndexMeta();
        index.setName(uniqueAnno.name());
        index.setUnique(true);
        index.setColumns(uniqueAnno.columns());
        indexes.add(index);
    }

    private static void addRegularIndex(_DDL_CompoundIndex indexAnno, List<IndexMeta> indexes) {
        IndexMeta index = new IndexMeta();
        index.setName(indexAnno.name());
        index.setUnique(false);
        index.setColumns(indexAnno.columns());
        indexes.add(index);
    }
}